Représentation 3D d'un tableau 2D

La reproduction interdite

René MagritteLa reproduction interdite

La Reproduction interdite est une huile sur toile peinte en 1937.

Le tableau représente un homme brun regardant de dos dans un miroir qui ne reflète pas le visage du personnage mais son dos. Il est donc impossible de voir le visage du personnage en question.
Un livre placé sur le rebord devant le miroir se reflète correctement dans le coin inférieur droit du tableau. Ce livre est une copie du roman Les Aventures d'Arthur Gordon Pym de l'auteur américain Edgar Allan Poe, l'un des auteurs préférés du peintre.

Description technique

[x] Objets 3D

Premièrement je me suis concentré sur les objets 3D, pour ce faire chaque objet 3D est stocké dans sa function à lui.
Après, j'ai commencé par créer avec des new THREE.BoxGeometry( w, h, l ), murMaterial ), la box qui comporterait l'ensemble des éléments du tableau.
Par la suite, je devais créer les objets 3D du tableau, c'est-à-dire le meuble, le cadre du miroir, le personnage et le livre. Pour créer le meuble et le cadre du tableau, j'ai continué à utiliser des BoxGeometry. Mais pour le personnage et le livre, ce sont des OBJ qui ont été créés ou fortement modifier sur Blender avec un lissage des vertex ainsi qu'une optimisation de la taille en Ko.
Ces derniers ont été ensuite chargés sur notre scène grâce à OBJLoader.js et pour des textures intégrer au modèle 3D, j'ai dû utiliser MTLLoader.js pour charger les textures.

[x] Brouillard

Pour créer un brouillard, il suffit d'utiliser THREE.Fog avec en paramètre une couleur, un near et un far.

[x] Effet miroir

Concernant l'effet de miroir, nous avons besoin de:
- Une surface : le miroir sert d'écran pour projeter ce qu'une caméra regarde, dans notre cas j'ai utilisé une BoxGeometry sur lequel j'applique comme texture d'environnement map envMap:cubeRenderTarget.texture qui est pour traduire, ce que regarde la caméra utilisée pour le miroir
- Une caméra : j'ai pris un CubeCamera au lieu de PerspectiveCamera, que ne prendre pas en compte de perspective, et qui prend en paramètre un near, un far et un renderTarget
- Un double de la box: comme nous ne pouvons pas filtrer les objets visibles de la caméra, pour respecter le plus possible le tableau, j'ai créé un double de la scène avec les objets voulus et la camera film se double

[x] Eclairage

Concernant les sources de lumières, nous en avons 4:
- 1 AmbientLight : cela applique une couleur et à l'ensemble de la pièce de façon uniforme
- 1 SpotLight : utilisé pour l'éclairage du personnage utilisé et les ombres portées
- 2 PointLight : utilisé pour l'éclairage du double de la box pour le miroir et pour éclairer l'ensemble de la scène pour les reflets spéculaires

[x] Ombres portées

Pour appliquer des ombres portés à la scène, je dois appliquer le paramètre les booléans de source des ombres (castShadow = true), et l'affichage des ombres sur un objet (receiveShadow = true).
Dans notre cas, nous avons le personnage que à castShadow = true et nous avons le solidGround (mer), le sol, meuble, le miroir, le livre qui ont receiveShadow = true.

[x] Texture avec transparence

La seule texture transparente de la scène concerne les portails qui sont des THREE.SpriteMaterial avec l'option transparent: true pour permet l'activation de la transparence.

[x] Sprites

Les Sprites que je suis permis de faire sont la référence des portails de la série "Rick et Morty", ces sprites contenu dans un THREE.SpriteMaterial avec pour textures, une map et une normalMap pour avoir l'impression d'un objet 3D.

[x] Environment map

L'Environment map, n'avait pas beaucoup d'intérêt dans mon tableau à part pour le miroir, mais comme il en fallait une autre, j'ai créé une grande PlaneGeometry avec une envMap appliqué pour faire penser à une mer calme en le voyant.

[x] Skybox

Concernant la skybox, j'ai voulu faire un fond qui rappelle l'espace. Pour faire une bonne skybox étoilé, j'ai utilisé que 6 images pour la faire, car étant donné que les images sont très sombres, nous ne verrons pas les brisures de la skybox

[x] specular/normal maps

Ce projet n'utilise pas de specularMap car il n'y en avait pas l'obligation d'en avoir par rapport à mon tableau. Mais concernant les normalMap, tout objet 3D utilisant une texture appelée depuis le dossier "/textures/" a par la même occasion appliqué une normale de la texture sur l'objet 3D.

[x] Shaders

Les Shaders sont composés d'une variable fragment shader et vertex shader que l'on applique sur le matériau THREE.ShaderMaterial. Pour le shader en question, j'ai décidé de créer un shader qui applique toutes les couleurs de spectre visible sur une THREE.SphereGeometry.

[x] Interaction par GUI

Concernant les interactions par le GUI, j'ai décidé de créer:
- L'affichage des axes et grilles XYZ : venu et revu en cours, cette méthode ne devrait être inconnue pour personne
- Le spot camera : cette interaction est utilisée pour mettre la caméra sur un certain pour de vue, permet dans le cas présent de voir tous les éléments de la scène sans difficultés. Les coordonnées de la position sont stockées dans une fonction spot et appelé par le bouton de l'interface GUI
- Le zoom max : j'ai mis la possiblité de faire un zoom par rapport a les hauteurs en pixels de notre écran (window.innerHeight) car la taille de base de notre tableau est assez petit avec canvasHeight = 503 et canvasWidth = 400. Notre scène, respect l'aspect ratio du tableau d'origine qui est à peu près du 0.8 : 1
- La visibilité : certains éléments de notre tableau doivent devenir invisibles pour permettre de voir le reste des éléments de la scène, c'est le cas des murs qui servent a accentué la ressemblance par rapport au tableau d'origine. Pour cela, il suffit de faire créer une booléan et l'appliquer à la variable visible et mettre la vérification de l'état du booléan dans render()
- La rotation du personnage : j'ai donné la possibilité au personnage faire une rotation sur lui-même, pour permettre à l'observateur de voir que le miroir n'est pas juste une image statique comme un png et autres. Pour faire cette rotation, j'ai créé une variable dans le GUI contenant la valeur par défaut, et je permets au GUI de faire varier cette valeur entre -180 et 180. Ensuite, il suffit de créer la rotation depuis la méthode render() avec : body.rotation.y = effectController.personnageAngle * Math.PI / 180
- Les resets : ces interactions sont identiques à l'interaction spot caméra, elles contiennent juste la rotation par défaut du personnage et la position par défaut de la caméra Observateur

[x] Animation

Il y a un total de 4 animations sur cette scène, une utilise le système de Tweening.
Mais pour les autres, j'ai décidé de faire des animations à mouvement circulaire. Pour cela, j'ai créé les variables animation et temps, qui augmentent leurs valeurs à chaque itération de la méthode render() qui est une boucle infinie. J'applique donc ces variables sur les positions des objets, et pour qu'il tourne autour d'un point, j'utilise les fameux Math.cos et Math.sin, les deux réunis donnent : object.position.x = 100 * Math.cos( animation * Math.PI / 180 ).
Cette méthode est utilisée pour les animations des portails, de la planète Terre, et la sphère de shaders.

[x] Tweening

En utilisant Tween.js, j'ai fait une animation de Cubes que augmentent et diminue leur scale de façon linéaire et se déplaçant dans une zone donnée.